package langchain4j.tools;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import dev.langchain4j.agent.tool.P;
import dev.langchain4j.agent.tool.Tool;
import langchain4j.bean.Appointment;
import langchain4j.entity.Department;
import langchain4j.entity.Doctor;
import langchain4j.entity.DoctorSchedule;
import langchain4j.service.AppointmentService;
import langchain4j.service.DepartmentService;
import langchain4j.service.DoctorService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.*;

/**
 * @author Yzc
 * 处理医疗预约挂号相关的业务逻辑
 */
@Component
@Slf4j
public class AppointmentTools {

    @Autowired
    private AppointmentService appointmentService;
    @Autowired
    private DoctorService doctorService;
    @Autowired
    private DepartmentService departmentService;

    @Tool(name = "预约挂号", value = "根据参数，先执行工具方法queryDepartment查询是否可预约，并直接给用户回答是否可预约，" +
            "并让用户确认所有预约信息(要确认用户的身份证和用户名)，用户确认后再进行预约。如果用户没有提供具体的医生姓名，请从向量存储中找到一位医生。")
    public String bookAppointment(Appointment appointment) {

        //查找数据库中是否包含对应的预约记录
        Appointment appointmentDB = appointmentService.getOne(appointment);

        if (appointmentDB == null) {
            appointment.setId(null);//防止大模型幻觉设置了id
            appointment.setStatus("booked");
            if (appointmentService.save(appointment)) {
                return "预约成功，并返回预约详情";
            } else {
                return "预约失败";
            }
        }
        return "您在相同的科室和时间已有预约";
    }

    @Tool(name = "取消预约挂号", value = "根据参数，查询预约是否存在，如果存在则删除预约记录并返回取消预约成功，否则返回取消预约失败")
    public String cancelAppointment(Appointment appointment) {

        Appointment appointmentDB = appointmentService.getOne(appointment);
        if (appointmentDB != null) {
            //删除预约记录
            LambdaUpdateWrapper<Appointment> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(Appointment::getId, appointmentDB.getId());
            updateWrapper.set(Appointment::getStatus, "cancelled");
            if (appointmentService.update(updateWrapper)) {
                return "取消预约成功";
            } else {
                return "取消预约失败";
            }
        }

        //取消失败
        return "您没有预约记录，请核对预约科室和时间";
    }

    @Tool(name = "查询科室的医生列表",
            value = "根据科室名称查询该科室下的所有医生信息，包括姓名、职称和专长")
    public String getDoctorsByDepartment(
            @P(value = "科室名称") String departmentName) {
        try {
            // 1. 先查询科室信息（注意：这里可能返回多个科室）
            List<Department> departments = departmentService.getDepartmentByName(departmentName.trim());

            if (departments.isEmpty()) {
                return String.format("【查询结果】未找到'%s'科室", departmentName);
            }

            // 2. 收集所有医生信息
            StringBuilder sb = new StringBuilder();
            for (Department dept : departments) {
                List<Doctor> doctors = doctorService.getDoctorsByDepartmentId(dept.getId());

                if (doctors.isEmpty()) {
                    sb.append(String.format("【%s】暂无医生信息\n\n", dept.getName()));
                    continue;
                }

                sb.append(String.format("【%s】有以下医生：\n", dept.getName()));
                doctors.forEach(doctor -> sb.append(
                        String.format("- %s (%s)\n  专长：%s\n\n",
                                doctor.getName(),
                                doctor.getTitle(),
                                doctor.getIntroduction())
                ));
            }

            return sb.toString();

        } catch (Exception e) {
            return String.format("【查询失败】无法获取'%s'科室的医生列表，原因：%s",
                    departmentName, e.getMessage());
        }
    }


    @Tool(name = "查询是否有号源",
            value = "根据医生姓名，日期和时间查询是否有号源(已经过了的时间不再推荐)")
    public String queryAppointment(
            @P(value = "医生姓名", required = false) String doctorName,
            @P(value = "科室名称", required = false) String department,
            @P(value = "日期") String date,
            @P(value = "时间，可选值：上午、下午") String time) {

        if (StringUtils.isBlank(doctorName)) {
            throw new IllegalArgumentException("必须提供医生姓名或科室名称");
        }


        log.info("查询号源参数 - 科室: {}, 日期: {}, 时间: {}, 医生: {}",
                department, date, time, doctorName);
        List<DoctorSchedule> schedules = doctorService.getDoctorSchedule(doctorName);
        StringBuilder sb = new StringBuilder();
        sb.append("日期\t\t时间段\t最大预约数\t已预约数\n");
        sb.append("----------------------------------------\n");
        schedules.forEach(s ->
                sb.append(String.format("%s\t%s\t%d\t\t%d\n",
                        s.getDate(),
                        s.getTimePeriod(),
                        s.getMaxAppointments(),
                        s.getCurrentAppointments()))
        );
        return sb.toString();
    }


}